package xyz.ibenben.zhongdian.common.shiro;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import xyz.ibenben.zhongdian.common.exception.ExceptionEnum;
import xyz.ibenben.zhongdian.common.exception.MyException;
import xyz.ibenben.zhongdian.common.job.NewJob;
import xyz.ibenben.zhongdian.common.job.QuartzManager;
import xyz.ibenben.zhongdian.common.redis.ShiroCache;
import xyz.ibenben.zhongdian.common.util.DateUtils;
import xyz.ibenben.zhongdian.system.entity.sys.SysUser;
import xyz.ibenben.zhongdian.system.service.sys.SysUserService;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 限制登录出错类
 * 限制登录次数，如果5次出错，锁定1个小时
 * 1小时后需要通过管理员解除限制，这里可以考虑使用定时任务来处理数据
 *
 * @author chenjian
 * @since 2017年10月18日下午5:17:22
 */
public class LimitRetryHashedMatcher extends HashedCredentialsMatcher {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 匹配
     *
     * @param token 参数
     * @param info  参数
     * @return 返回值
     */
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        String username = (String) token.getPrincipal();
        ShiroCache<String, Object> shiroCache = new ShiroCache<>("passwordRetry", redisTemplate);
        //retrycount + 1
        Object element = shiroCache.get(username);
        if (element == null) {
            shiroCache.put(username, 1);
            element = 0;
        } else {
            element = Integer.parseInt(element.toString()) + 1;
            shiroCache.put(username, element);
        }
        AtomicInteger retryCount = new AtomicInteger(Integer.parseInt(element.toString()));
        //重试5次后不对，限制用户登录
        if (retryCount.incrementAndGet() > 5) {
            //if retrycount >5 throw
            SysUser user = sysUserService.selectByUsername(username);
            user.setEnable(0);
            sysUserService.updateAll(user, null);
            Map<String, Object> map = new HashMap<>();
            map.put("sysUserService", sysUserService);
            map.put("userId", user.getId());
            Date date = DateUtils.setHourNew(new Date(), +1);
            //一小时后执行把数据从数据库中更新为可用
            QuartzManager.addJob("jobLimit", NewJob.class, DateUtils.translation(date), map);
            //在同一异常管理中抛出此异常，并处理该用户
            throw new MyException(ExceptionEnum.PROCESSUSERLIMITEXCEPTION, new ExcessiveAttemptsException(), user.getId());
        }
        boolean matches = super.doCredentialsMatch(token, info);
        if (matches) {
            //清除重试次数
            shiroCache.remove(username);
        } else {
            //重新匹配
            info.getCredentials();
            matches = super.doCredentialsMatch(token, info);
        }
        return matches;
    }
}
